using Cairo;
using Gtk;

namespace Ribbons {

	/** Toggle button to be used in Ribbons. */
	public class ToggleButton : BaseButton {

		protected const double LINE_WIDTH = 1.0;

		public signal void value_changed ();

		private bool _value;
		public bool value {
			set {
				if (_value != value) {
					_value = value;
					value_changed ();
				}
			}
			get { return _value; }
		}

		/** Construction method */
		construct {
			set_flags (get_flags () | WidgetFlags.NO_WINDOW);

			add_events (Gdk.EventMask.BUTTON_PRESS_MASK
						| Gdk.EventMask.BUTTON_RELEASE_MASK
						| Gdk.EventMask.POINTER_MOTION_MASK);
			
			this.padding = 2;
			this.image_position = PositionType.TOP;
			_is_small = false;
			_enabled = true;
			_value = false;
		}

		/**
		 * Constructor given a label to display.
		 *
		 * @param label  Label to display.
		 */
		public ToggleButton.with_label (string label) {
			this.label = label;
		}

		/**
		 * Constructor given an image to display.
		 *
		 * @param image  Image to display
		 */
		public ToggleButton.with_image (Image image) {
			this.image = image;
		}

		/**
		 * Constructor given a label and an image to display.
		 *
		 * @param image  Image to display.
		 * @param label  Label to display.
		 */
		public ToggleButton (Image image, string label) {
			this.image = image;
			this.label = label;
		}

		/**
		 * Constructs a Button from a stock.
		 *
		 * @param name   Name of the stock.
		 * @param large  <b>true</b> if the image should be large,
		 *               <b>false</b> otherwise.
		 */
		public static ToggleButton from_stock (string name, bool large) {
			var image = new Image.from_stock (name, large ? IconSize.LARGE_TOOLBAR
														  : IconSize.SMALL_TOOLBAR);
			var button = new ToggleButton.with_image (image);
			if (!large) {
				button.image_position = PositionType.LEFT;
			}
			return button;
		}

		/**
		 * Constructs a Button from a stock.
		 *
		 * @param name   Name of the stock.
		 * @param label  Label to display.
		 * @param large  <b>true</b> if the image should be large,
		 *               <b>false</b> otherwise.
		 */
		public static ToggleButton from_stock_with_label (string name, string label, bool large) {
			var image = new Image.from_stock (name, large ? IconSize.LARGE_TOOLBAR
														  : IconSize.SMALL_TOOLBAR);
			var button = new ToggleButton (image, label);
			if (!large) {
				button.image_position = PositionType.LEFT;
			}
			return button;
		}

		protected override bool bound_widget_button_press_event (Widget sender,
														Gdk.EventButton evnt) {
			button_press_event (evnt);
			return false;
		}

		protected override bool bound_widget_button_release_event (Widget sender,
														Gdk.EventButton evnt) {
			button_release_event (evnt);
			this.value = !this.value;
			queue_draw ();
			return false;
		}

		protected override void size_request (out Requisition requisition) {
//			base.size_request (out requisition);	// XXX-GEETK

			Requisition child_requisition = Requisition ();
			if (this.child != null && this.child.visible) {
				this.child.size_request (out child_requisition);
			}

			if (this.height_request == -1) {
				requisition.height = child_requisition.height
										+ (int) (LINE_WIDTH * 4 + _padding * 2);
			}
			if (this.width_request == -1) {
				requisition.width = child_requisition.width
										+ (int) (LINE_WIDTH * 4 + _padding * 2);
			}
		}

		protected override void size_allocate (Gdk.Rectangle alloc) {
			base.size_allocate (alloc);
			Gdk.Rectangle allocation = alloc;	// XXX-GEETK

			allocation.x += (int) (LINE_WIDTH * 2 + _padding);
			allocation.y += (int) (LINE_WIDTH * 2 + _padding);
			allocation.height -= (int) (LINE_WIDTH * 4 + _padding * 2);
			allocation.width -= (int) (LINE_WIDTH * 4 + _padding * 2);

			if (allocation.height < 0) {
				allocation.height = 0;
			}
			if (allocation.width < 0) {
				allocation.width = 0;
			}

			if (this.child != null && this.child.visible) {
				this.child.size_allocate (allocation);
			}
		}

		protected override bool expose_event (Gdk.EventExpose evnt) {
			var cr = Gdk.cairo_create (this.window);

			cr.rectangle (evnt.area.x, evnt.area.y,
							evnt.area.width, evnt.area.height);
			cr.clip ();
			draw (cr);

//			cr.target.dispose ();	// XXX-GEETK
//			cr.dispose ();

			return base.expose_event (evnt);
		}

		protected void draw (Context cr) {
			var rect = Gdk.Rectangle () {
				x = this.allocation.x,
				y = this.allocation.y,
				width = this.allocation.width,
				height = this.allocation.height
			};
			double round_size = _is_small ? 2.0 : 3.0;
			var s = _state;
			if (_value == true) {
				s = Theme.ButtonState.PRESSED;
			}
			_theme.draw_button (cr, rect, s, round_size, LINE_WIDTH, 0, 0, false, this);
		}

		protected override bool button_press_event (Gdk.EventButton evnt) {
//			bool ret = base.button_press_event (evnt);		// XXX-GEETK
			bool ret = false;
			_state = Theme.ButtonState.PRESSED;
			if (!_enabled) {
				_state = Theme.ButtonState.DEFAULT;
			}
			queue_draw ();
			return ret;
		}

		protected override bool button_release_event (Gdk.EventButton evnt) {
//			bool ret = base.button_release_event (evnt);	// XXX-GEETK
			bool ret = false;
			_state = Theme.ButtonState.HOVER;
			if (!_enabled) {
				_state = Theme.ButtonState.DEFAULT;
			}
			queue_draw ();
			return ret;
		}

		protected override bool enter_notify_event (Gdk.EventCrossing evnt) {
//			bool ret = base.enter_notify_event (evnt);		// XXX-GEETK
			bool ret = false;
			_state = Theme.ButtonState.HOVER;
			if (!_enabled) {
				_state = Theme.ButtonState.DEFAULT;
			}
			queue_draw ();
			return ret;
		}

		protected override bool leave_notify_event (Gdk.EventCrossing evnt) {
//			bool ret = base.leave_notify_event (evnt);		// XXX-GEETK
			bool ret = false;
			_state = Theme.ButtonState.DEFAULT;
			queue_draw ();
			return ret;
		}
	}
}
